package com.example.demo.core.component;

import com.alibaba.fastjson.TypeReference;
import com.example.demo.core.annotations.ApiNotNull;
import com.example.demo.core.exception.ProgramException;
import com.example.demo.core.util.JsonUtil;
import com.example.demo.core.util.RegexUtil;
import com.example.demo.core.util.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author yj
 * @date 2021-08-17 22:33
 */
@Slf4j
@Component
public class RedisComponent {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public boolean set(@ApiNotNull String key, @ApiNotNull Object value, @ApiNotNull Long expire, @ApiNotNull TimeUnit timeUnit) {
        try {
            if (value instanceof String) {
                redisTemplate.opsForValue().set(key, (String) value, expire, timeUnit);
            } else {
                redisTemplate.opsForValue().set(key, JsonUtil.toJson(value), expire, timeUnit);
            }
            return true;
        } catch (Exception e) {
            log.error("当前为redis写入String数据,异常信息：{}", e.getMessage());
            return false;
        }
    }

    public boolean set(@ApiNotNull String key, @ApiNotNull Object value) {
        try {
            if (value instanceof String) {
                redisTemplate.opsForValue().set(key, (String) value);
            } else {
                redisTemplate.opsForValue().set(key, JsonUtil.toJson(value));
            }
            return true;
        } catch (Exception e) {
            log.error("当前为redis写入String数据,异常信息：{}", e.getMessage());
            return false;
        }
    }

    /**
     * 获取制定key的内容，没有返回null
     *
     * @param key 键
     */
    public String get(@ApiNotNull String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 获取指定key的内容，并且转换成对应的类型
     *
     * @param key           键
     * @param typeReference 类型
     */
    public <T> T get(@ApiNotNull String key, @ApiNotNull TypeReference<T> typeReference) {
        try {
            String value = get(key);
            if (RegexUtil.checkStringIsNotNull(value)) {
                return JsonUtil.jsonObjectToType(value, typeReference);
            }
            throw new ProgramException("当前方法为:" + ThreadUtil.getMethodName() + ",获取数据key:" + key + ",value:" + value);
        } catch (Exception e) {
            log.error("当前为获取数据异常：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取指定key的内容，并且转换成对应的类型
     *
     * @param key   键
     * @param clazz 类型
     */
    public <T> T get(@ApiNotNull String key, @ApiNotNull Class<T> clazz) {
        try {
            String value = get(key);
            if (RegexUtil.checkStringIsNotNull(value)) {
                return JsonUtil.jsonObjectToType(value, clazz);
            }
            throw new ProgramException("当前方法为:" + ThreadUtil.getMethodName() + ",获取数据key:" + key + ",value:" + value);
        } catch (Exception e) {
            log.error("当前为获取数据异常：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 判断某个键值对是否存在
     *
     * @param key 键
     */
    public Boolean hasKey(@ApiNotNull String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 删除指定元素
     *
     * @param key 键
     */
    public Boolean removeKey(@ApiNotNull String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 批量删除key
     *
     * @param keys 键值集合
     * @return 是否删除成功
     */
    public Boolean removeKeys(@ApiNotNull List<String> keys) {
        try {
            //先过滤掉不存在的缓存
            keys = keys.stream().filter(this::hasKey).collect(Collectors.toList());
            //删除行数
            Long removeNum = Optional.ofNullable(redisTemplate.delete(keys)).orElse(0L);
            //如果删除数等于传递进来的list大小，则返回正常
            if (removeNum != keys.size()) {
                //判断key存不存在
                removeKeys(keys);
            }
            return true;
        } catch (Exception e) {
            log.error("当前为方法:{},传递参数为:{},异常信息为:{}", ThreadUtil.getMethodName(), keys, e.getMessage());
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param value 要增加几(大于0)
     */
    public Long increase(@ApiNotNull String key, @ApiNotNull Long value, @ApiNotNull Long time) {
        if (value < 0) {
            throw new ProgramException("递增因子必须大于0");
        }
        Long increment = redisTemplate.opsForValue().increment(key, value);
        expire(key, time);
        return increment;
    }

    /**
     * 递减
     *
     * @param key   键
     * @param value 要减少几(大于0)
     */
    public Long decrease(@ApiNotNull String key, @ApiNotNull Long value, @ApiNotNull Long time) {
        if (value < 0) {
            throw new ProgramException("递增因子必须大于0");
        }
        Long increment = redisTemplate.opsForValue().increment(key, -value);
        expire(key, time);
        return increment;
    }


//    public boolean listSet(@ApiNotNull String key, @ApiNotNull List<Object> value, @ApiNotNull Long expire, @ApiNotNull TimeUnit timeUnit) {
//        try {
//            redisTemplate.opsForList().set(key, );
//            return true;
//        } catch (Exception e) {
//            log.error("当前为redis写入String数据,异常信息：{}", e.getMessage());
//            return false;
//        }
//    }


    public Boolean expire(@ApiNotNull String key, @ApiNotNull Long time) {
        return expire(key, time, TimeUnit.SECONDS);
    }

    public Boolean expire(@ApiNotNull String key, @ApiNotNull Long time, @ApiNotNull TimeUnit timeUnit) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取匹配规则的key
     *
     * @param key 不完整的一个key
     * @return 满足条件的key集合
     */
    public Set<String> keys(@ApiNotNull String pattern) {
        return redisTemplate.keys(pattern);
    }
}
